/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const success : int = 0
const fail    : int = 1

const TEST_DATA : {{.item.test_data_type}} = {{.item.test_data}};

function reverseTypedArrayBytes(buff: ArrayBuffer) {
    let typedArray = new {{.item.typed_array_type}}(buff)
    let elementSize = {{.item.typed_array_type}}.BYTES_PER_ELEMENT
    const uint8Array = new Uint8Array(new ArrayBuffer(elementSize))
    const reversedBuffer = new ArrayBuffer(typedArray.length * elementSize)
    const reversedView = new Uint8Array(reversedBuffer)
    for (let i = 0; i < typedArray.length; i++) {
        // Copy bytes into the buffer
        uint8Array.set(new Uint8Array(typedArray.buffer, i * elementSize, elementSize))
        // Reverse the bytes and set them into the reversed view
        for (let j = 0; j < elementSize; j++) {
            reversedView[i * elementSize + j] = uint8Array[elementSize - 1 - j]
        }
    }
    return reversedBuffer
}

function testProps(value: {{.item.primitive_type}}): int {
    const buffer = new ArrayBuffer({{.item.byte_length}})
    const view = new DataView(buffer)
    view.set{{.item.setter_getter_base}}(0, value, true)
    const actual = view.get{{.item.setter_getter_base}}(0, true)
    let failures = 0

    if ((new Number(view.get{{.item.setter_getter_base}}(0, true))).toPrecision({{.item.precision}}) != (new Number(value)).toPrecision({{.item.precision}})) {
        console.log("Value check for `{{.item.setter_getter_base}}` with value " + value + " failed, expected: " + value + ", actual: " + actual)
        failures++
    }

    const reversed =
        new DataView(reverseTypedArrayBytes(buffer))
            .get{{.item.setter_getter_base}}(0, false)
    if ((new Number(value)).toPrecision({{.item.precision}}) != (new Number(reversed)).toPrecision({{.item.precision}})) {
        console.log("Reverse endiness check for `{{.item.setter_getter_base}}` with value " + value + " failed, expected: " + reversed + ", actual: " + reversed)
        failures++
    }

    if (failures > 0) {
        return fail
    }
    return success
}

function testMultiple(value: {{.item.primitive_type}}): int {
    const buffer = new ArrayBuffer({{.item.byte_length}})
    const view = new DataView(buffer)
    const elementLength: int = {{.item.element_length}}
    const elementsCount = Math.trunc({{.item.byte_length}} / elementLength).toInt()
    let failures = 0
    for (let i: int = 0; i < elementsCount; ++i) {
        view.set{{.item.setter_getter_base}}(i * elementLength, value)
    }

    const goldString = new Number(value).toPrecision({{.item.precision}})

    for (let i: int = 0; i < elementsCount; ++i) {
        const fromBuffer = new Number(view.get{{.item.setter_getter_base}}(i * elementLength))
        const fromBufferString = fromBuffer.toPrecision({{.item.precision}})
        if (fromBufferString != goldString)
        {
            console.log(
                "Error for set&get in DataView with byte_length={{.item.byte_length}}," +
                " for {{.item.target_element_type}} at pos=" + (i * elementLength) +
                " expected: " + goldString + ", but given: " + fromBufferString
            )
            failures += 1
        }
    }
    return failures
}


function main(): int {
    let failures = 0
    let test_cases_length: int = TEST_DATA.length
    for (let i: int = 0; i < test_cases_length; i++) {
        failures += testProps(TEST_DATA[i])
        failures += testMultiple(TEST_DATA[i])
    }
    if (failures > 0) {
        console.log("Failed")
        return fail
    }
    console.log("All passed")
    return 0
}
